
/*--------------------------初始化场景------------------------------*/
export default function initScene ()  {
  let el = document.body;
  let width = window.innerWidth;
  let height = window.innerHeight;
  // 渲染
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.outputEncoding = THREE.sRGBEncoding;
  
  el.appendChild(renderer.domElement);
  renderer.setSize(width, height);
  renderer.setClearColor(0xeeeeee);
  renderer.shadowMap.enabled = true;

  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.domElement.style.position = "absolute";
  labelRenderer.domElement.style.top = "0";
  document.body.appendChild(labelRenderer.domElement);

  // 相机&场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xf0f0f0);
  camera = new THREE.PerspectiveCamera(75, width / height, 1, 15000);
  camera.up.set(0, 1, 0);
  camera.position.set(...cameraPos);
  // 控件

  control =new OrbitControls(camera, labelRenderer.domElement);
  control.target.set(-0.1, 0, 0);
  // 光线
  const fillLight1 = new THREE.HemisphereLight( 0x4488bb, 0x002244, 0.5 );
  fillLight1.position.set( 2, 1, 1 );
  scene.add( fillLight1 );

  const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
  directionalLight.position.set( - 5, 25, - 1 );
  directionalLight.castShadow = true;
  directionalLight.shadow.camera.near = 0.01;
  directionalLight.shadow.camera.far = 500;
  directionalLight.shadow.camera.right = 30;
  directionalLight.shadow.camera.left = - 30;
  directionalLight.shadow.camera.top	= 30;
  directionalLight.shadow.camera.bottom = - 30;
  directionalLight.shadow.mapSize.width = 1024;
  directionalLight.shadow.mapSize.height = 1024;
  directionalLight.shadow.radius = 4;
  directionalLight.shadow.bias = - 0.00006;
  scene.add( directionalLight );
  // 雾化
  scene.background = new THREE.Color( 0xa0a0a0 );
  scene.fog = new THREE.Fog( 0xa0a0a0, 1, 50 );
  // scene.background = new THREE.Color( 0x88ccee );
  // scene.fog = new THREE.Fog( 0x88ccee, 0, 50 );

  sky()
  loadModel()
  resize()
  if(showCollider) scene.add(sphere1,sphere2,body)
  if(showHelper)initGrid()
};
// 页面尺度改变时 重置相机比例
const resize = () => {
  const windowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  };

  window.addEventListener("resize", windowResize);
};
// 加载辅助线
const initGrid=()=>{
  const grid = new THREE.GridHelper( 100, 20, 0x000000, 0x000000 );
  grid.material.opacity = 0.2;
  grid.material.transparent = true;
  scene.add(grid,new THREE.AxesHelper(1000,1000,1000));
}

// 加载天空
const sky = () => {
  const shader_v = `
    varying vec3 vWorldPosition;
    void main() {
    vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
    vWorldPosition = worldPosition.xyz;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }`;
  const shader_f = `
    uniform vec3 topColor;
    uniform vec3 bottomColor;
    uniform float offset;
    uniform float exponent;
    varying vec3 vWorldPosition;
    void main() {
      float h = normalize( vWorldPosition + offset ).y;
      gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h, 0.0 ), exponent ), 0.0 ) ), 1.0 );
    }`;
  // 天空模型
  const uniforms = {
    topColor: { value: new THREE.Color(0x0077ff) },
    bottomColor: { value: new THREE.Color(0xffffff) },
    offset: { value: 400 },
    exponent: { value: 0.6 },
  };
  uniforms.topColor.value.copy(
    uniforms.topColor.value.copy(new THREE.Color(0xaabbff))
  );
  const skyGeo = new THREE.SphereGeometry(4000, 32, 15);
  const skyMat = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: shader_v,
    fragmentShader: shader_f,
    // side:THREE.BackSide,
    side: THREE.DoubleSide,
    // map:getTexture(`/textures/earth1.jpg`)
  });
  let sky = new THREE.Mesh(skyGeo, skyMat);
  scene.add(sky);
};
// 加载云
function createCloud(){
  // Texture
  const size = 128;
  const data = new Uint8Array( size * size * size );

  let i = 0;
  const scale = 0.05;
  const perlin = new ImprovedNoise();
  const vector = new THREE.Vector3();

  for ( let z = 0; z < size; z ++ ) {
    for ( let y = 0; y < size; y ++ ) {
      for ( let x = 0; x < size; x ++ ) {
        const d = 1.0 - vector.set( x, y, z ).subScalar( size / 2 ).divideScalar( size ).length();
        data[ i ] = ( 128 + 128 * perlin.noise( x * scale / 1.5, y * scale, z * scale / 1.5 ) ) * d * d;
        i ++;
      }
    }
  }

  const texture = new THREE.Data3DTexture( data, size, size, size );
  texture.format = THREE.RedFormat;
  texture.minFilter = THREE.LinearFilter;
  texture.magFilter = THREE.LinearFilter;
  texture.unpackAlignment = 1;
  texture.needsUpdate = true;

  // Material
  const vertexShader = /* glsl */`
    in vec3 position;
    uniform mat4 modelMatrix;
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    uniform vec3 cameraPos;
    out vec3 vOrigin;
    out vec3 vDirection;
    void main() {
      vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
      vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
      vDirection = position - vOrigin;
      gl_Position = projectionMatrix * mvPosition;
    }
  `;
  const fragmentShader = /* glsl */`
    precision highp float;
    precision highp sampler3D;
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    in vec3 vOrigin;
    in vec3 vDirection;
    out vec4 color;
    uniform vec3 base;
    uniform sampler3D map;
    uniform float threshold;
    uniform float range;
    uniform float opacity;
    uniform float steps;
    uniform float frame;
    uint wang_hash(uint seed)
    {
        seed = (seed ^ 61u) ^ (seed >> 16u);
        seed *= 9u;
        seed = seed ^ (seed >> 4u);
        seed *= 0x27d4eb2du;
        seed = seed ^ (seed >> 15u);
        return seed;
    }
    float randomFloat(inout uint seed)
    {
        return float(wang_hash(seed)) / 4294967296.;
    }
    vec2 hitBox( vec3 orig, vec3 dir ) {
      const vec3 box_min = vec3( - 0.5 );
      const vec3 box_max = vec3( 0.5 );
      vec3 inv_dir = 1.0 / dir;
      vec3 tmin_tmp = ( box_min - orig ) * inv_dir;
      vec3 tmax_tmp = ( box_max - orig ) * inv_dir;
      vec3 tmin = min( tmin_tmp, tmax_tmp );
      vec3 tmax = max( tmin_tmp, tmax_tmp );
      float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
      float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
      return vec2( t0, t1 );
    }
    float sample1( vec3 p ) {
      return texture( map, p ).r;
    }
    float shading( vec3 coord ) {
      float step = 0.01;
      return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) );
    }
    void main(){
      vec3 rayDir = normalize( vDirection );
      vec2 bounds = hitBox( vOrigin, rayDir );
      if ( bounds.x > bounds.y ) discard;
      bounds.x = max( bounds.x, 0.0 );
      vec3 p = vOrigin + bounds.x * rayDir;
      vec3 inc = 1.0 / abs( rayDir );
      float delta = min( inc.x, min( inc.y, inc.z ) );
      delta /= steps;
      // Jitter
      // Nice little seed from
      // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/
      uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 );
      vec3 size = vec3( textureSize( map, 0 ) );
      float randNum = randomFloat( seed ) * 2.0 - 1.0;
      p += rayDir * randNum * ( 1.0 / size );
      //
      vec4 ac = vec4( base, 0.0 );
      for ( float t = bounds.x; t < bounds.y; t += delta ) {
        float d = sample1( p + 0.5 );
        d = smoothstep( threshold - range, threshold + range, d ) * opacity;
        float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2;
        ac.rgb += ( 1.0 - ac.a ) * d * col;
        ac.a += ( 1.0 - ac.a ) * d;
        if ( ac.a >= 0.95 ) break;
        p += rayDir * delta;
      }
      color = ac;
      if ( color.a == 0.0 ) discard;
    }
  `;

  const geometry = new THREE.BoxGeometry( 1, 1, 1 );
  const material = new THREE.RawShaderMaterial( {
    glslVersion: THREE.GLSL3,
    uniforms: {
      base: { value: new THREE.Color( 0x798aa0 ) },
      map: { value: texture },
      cameraPos: { value: new THREE.Vector3() },
      threshold: { value: 0.25 },
      opacity: { value: 0.25 },
      range: { value: 0.1 },
      steps: { value: 100 },
      frame: { value: 0 }
    },
    vertexShader,
    fragmentShader,
    side: THREE.BackSide,
    transparent: true
  } );

  cloud = new THREE.Mesh( geometry, material );
  cloud.position.set(0,0,0)

  cloud.rotation.x = -Math.PI / 2;
  scene.add( cloud );
          
  // 更新云的材质效果
  const parameters = {
    threshold: 0.25,
    opacity: 0.25,
    range: 0.1,
    steps: 100
  };
}
// 加载日落
function sunFall(){
  const sky = new Sky();
  sky.scale.setScalar(10000);
  sky.name = "Sky";
  scene.add(sky);

  const skyUniforms = sky.material.uniforms;

  skyUniforms["turbidity"].value = 10;
  skyUniforms["rayleigh"].value = 2;
  skyUniforms["mieCoefficient"].value = 0.005;
  skyUniforms["mieDirectionalG"].value = 0.8;

  const parameters = {
    elevation: 2,
    azimuth: 180
  };
  new THREE.PMREMGenerator(renderer);
  let sun = new THREE.Vector3();

  function updateSun() {
    const phi = THREE.MathUtils.degToRad(90 - parameters.elevation);
    const theta = THREE.MathUtils.degToRad(parameters.azimuth);

    sun.setFromSphericalCoords(1, phi, theta);

    sky.material.uniforms["sunPosition"].value.copy(sun);

  }

  updateSun();
}
// 加载地表环境
function loadModel(){
  const loader = new THREE.GLTFLoader().setPath( './source/models/' );
  loader.load( 'collision-world.glb', ( glb ) => {
    // loader.load( 'model.glb', ( glb ) => {
    let group=glb.scene
      scene.add( group );
      worldOctree.fromGraphNode( group );
      group.traverse( child => {
          if ( child.isMesh ) {
              child.castShadow = true;
              child.receiveShadow = true;
              if ( child.material.map ) {
                  child.material.map.anisotropy = 4;
              }
          }
      } );
  },function(xhr){
    let progress=Math.floor(xhr.loaded / xhr.total * 100)
    document.querySelector('.num').innerHTML=progress
    document.querySelector('.tube').style.width=progress+'%'
    if(progress===100){
      setTimeout(() => {
        document.querySelector('#loading').style.display='none'
      }, 500);
        
    }
  });

}
